// ------------------------------------------------------------------------------------------
// Licensed by Interprise Solutions.
// http://www.InterpriseSolutions.com
// For details on this license please visit  the product homepage at the URL above.
// THE ABOVE NOTICE MUST REMAIN INTACT.
// ------------------------------------------------------------------------------------------
using System;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Security.Cryptography;
using System.Text;
using InterpriseSuiteEcommerceCommon.Extensions;
using InterpriseSuiteEcommerceCommon.InterpriseIntegration.Authentication;
using System.Web.Security;

namespace InterpriseSuiteEcommerceCommon
{
    /// <summary>
    /// Summary description for Security: localization of password storage and comparision functions.
    /// </summary>
    public class Security
    {

        public struct SecurityParams
        {
            public string EncryptKey;
            public int KeySize;
            public int EncryptIterations;
            public string InitializationVector;
            public string HashAlgorithm;
        }

        public static readonly int ro_SaltKeyIsInvalid = 0;
        public static readonly int ro_PasswordIsInClearText = -1;
        public static readonly int ro_PasswordIsEncrypted = -2;
        public static readonly string ro_PasswordDefaultTextForAnon = String.Empty;
        public static readonly string ro_DecryptFailedPrefix = "Error.";

        public enum CryptTypeEnum
        {
            V1 = 0,
            V2 = 1
        }

        public Security() { }

        public static void AgeSecurityLog()
        {
            DB.ExecuteSQL("delete from SecurityLog where ActionDate < dateadd(year,-1,getdate())");
        }

        public static string GetMD5Hash(string s)
        {
            // Create a new instance of the MD5CryptoServiceProvider object.
            var md5Hasher = MD5.Create();

            // Convert the input string to a byte array and compute the hash.
            var data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(s));

            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            var sBuilder = new StringBuilder();

            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }

            // Return the hexadecimal string.
            return sBuilder.ToString();
        }
        
        public static string GetEncryptParam(string ParamName)
        {
            string param = string.Empty;
            if (ParamName == "EncryptKey")
            {
                param = CommonLogic.Application(ParamName);
                if (string.IsNullOrEmpty(param))
                {
                    param = AppLogic.AppConfig(ParamName);
                }
            }
            else
            {
                param = AppLogic.AppConfig(ParamName);
            }

            // now do validation!
            if (ParamName == "EncryptKey")
            {
                if (param.Length == 0 || param == "WIZARD" || param == AppLogic.ro_TBD)
                {
                    throw new ArgumentException("You must enter your EncryptKey in the /web.config file!!! Open that file in Notepad, and see the instructions.");
                }
            }

            if (ParamName == "EncryptIterations")
            {
                if (param.Length == 0 && !CommonLogic.IsInteger(param) && Convert.ToInt32(param) >= 1 && Convert.ToInt32(param)<= 4)
                {
                    throw new ArgumentException("The EncryptIterations parameter must be an integer value between 1 and 4.");
                }
            }

            if (ParamName == "InitializationVector")
            {
                if (param.Length == 0 || param == AppLogic.ro_TBD || param.Length != 16)
                {
                    throw new ArgumentException("You MUST set your InitializationVector in the AppConfig manager in the admin site! it MUST be exactly 16 characters/digits long. This is required for security reasons.");
                }
            }

            if (ParamName == "KeySize")
            {
                if (param.Length == 0 || param == "0" || (param != "128" && param != "192" && param != "256"))
                {
                    throw new ArgumentException("You MUST set your KeySize value in the AppConfig manager in the admin site to an allowed valid value! This is required for security reasons.");
                }
            }

            if (ParamName == "HashAlgorithm")
            {
                if (param.Length == 0 || (param != "MD5" && param != "SHA1"))
                {
                    throw new ArgumentException("You MUST set your HashAlgorithm in the AppConfig manager in the admin site to an allowed valid value! This is required for security reasons.");
                }
            }

            return param;
        }

        public static SecurityParams GetSecurityParams()
        {
            SecurityParams p;
            p.EncryptKey = GetEncryptParam("EncryptKey");
            p.HashAlgorithm = GetEncryptParam("HashAlgorithm");
            p.InitializationVector = GetEncryptParam("InitializationVector");
            p.KeySize = System.Int32.Parse(GetEncryptParam("KeySize"));
            p.EncryptIterations = System.Int32.Parse(GetEncryptParam("EncryptIterations"));
            if (p.EncryptIterations == 0)
            {
                p.EncryptIterations = 1;
            }
            return p;
        }

        public static string MungeString(string s)
        {
            return MungeString(s, string.Empty, GetSecurityParams());
        }

        public static string MungeString(string s, SecurityParams p)
        {
            return MungeString(s, string.Empty, p);
        }

        public static string MungeString(string s, string SaltKey)
        {
            return MungeString(s, SaltKey, GetSecurityParams());
        }

        public static string MungeString(string s, string SaltKey, SecurityParams p)
        {
            if (s.Length == 0)
            {
                return s;
            }
            // TBD:
            // Replace with IS-Specific encryption routine...            
            return s;
        }

        public static string UnmungeString(string s)
        {
            return Security.UnmungeString(s, String.Empty, GetSecurityParams());
        }

        public static string UnmungeString(string s, SecurityParams p)
        {
            return Security.UnmungeString(s, String.Empty, p);
        }

        public static string UnmungeString(string s, string SaltKey)
        {
            return Security.UnmungeString(s, SaltKey, GetSecurityParams());
        }

        public static string UnmungeString(string s, string SaltKey, SecurityParams p)
        {
            if (s.Length == 0)
            {
                return s;
            }
            try
            {
                // TBD:
                // Replace with IS-Specific encryption routine...
                return s;
            }
            catch
            {
                //return "Error: Decrypt Failed";
                // to make sure when comparing the StartsWith
                return ro_DecryptFailedPrefix + " Decrypt Failed";
            }
        }

        public static string JavascriptEscape(string s)
        {
            return s.ToJavaScriptEscape();
        }

        public static string JavascriptEscapeClean(string s)
        {
            return CommonLogic.CleanLevelFive(JavascriptEscape(s));
        }

        public static string RemoveNewLines(string input)
        {
            return input.Replace("\n", string.Empty).Replace("\r", string.Empty);
        }

        public static string HtmlEncode(string text)
        {
            return RemoveNewLines(text).ToHtmlEncode();
        }

        public static string UrlEncode(string text)
        {
            return text.ToUrlEncode();
        }

        public static string HtmlDecode(string text)
        {
            return text.ToHtmlDecode();
        }

        public static string UrlDecode(string text)
        {
            return text.ToUrlDecode();
        }

        /// <summary>
        /// This will only be used for web methods that requires authentication or needs to be secured
        /// </summary>
        public static void AuthenticateService()
        {
            string message = DomainConstants.SERVICE_TOKEN_FAILED;
            string token = HttpContext.Current.Request.Headers[DomainConstants.SERVICE_TOKEN];
            if (token.IsNullOrEmptyTrimmed()) throw new Exception(message); ;

            var customer = Customer.Current;
            try
            {
                string code = GetMD5Hash(customer.CustomerCode);
                if (token != code) throw new Exception(message);
            }
            catch (Exception)
            {
                throw new Exception(message);
            }
        }

        public static bool IsAdminCurrentlyLoggedIn()
        {
            var authCookie = HttpContext.Current.Request.Cookies[".ADMINAUTH"];

            if (authCookie == null) return false;

            string userName = authCookie.Value;
            var ticket = FormsAuthentication.Decrypt(userName);
            var account = ISSIUserAccount.Find(ticket.Name);

            //If account exist from auth cookies return true

            return (account != null);
        }

    }
}
